package com.iot.ic.common.utils;

import java.util.ArrayList;
import java.util.List;

import org.bson.codecs.configuration.CodecRegistry;
import org.bson.conversions.Bson;

import com.mongodb.BasicDBObject;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientURI;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.MongoIterable;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;

/**
 * @Class: MongodbHelper <br>
 * @Desp: MongoDb帮助类
 * @Author  songxy <br>
 * @Date: 2015/12/30  15:56 <br>
 * @version 1.0.0
 */
public class MongodbHelper {

    private static final String PROTOCAL = "mongodb";
    private MongoClient mongoClient;
    private MongoDatabase mongoDatabase;
    private String mName;

    public MongodbHelper(String ip, int port, String username , String password, String dbName) {
        if (ip == null) {
            throw new IllegalArgumentException(ip + " is NULL");
        }
        if (port > 65534 || port < 0) {
            throw new IllegalArgumentException(port + " Out of Bounds");
        }

        MongoClientURI uri = new MongoClientURI(PROTOCAL.concat("://").concat(username)
                            .concat(":").concat(password).concat("@").concat(ip).concat(":")
                            .concat(String.valueOf(port).concat("/").concat(dbName)));
        mongoClient = new MongoClient(uri);
//        mongoClient.setReadPreference(ReadPreference.secondaryPreferred());
        mongoDatabase = mongoClient.getDatabase(uri.getDatabase());
        this.mName = dbName;
    }

    public MongodbHelper(String ip, int port, String dbName) {
        if (ip == null) {
            throw new IllegalArgumentException(ip + " is NULL");
        }
        if (port > 65534 || port < 0) {
            throw new IllegalArgumentException(port + " Out of Bounds");
        }

        mongoClient = new MongoClient(ip, port);
        mongoDatabase = mongoClient.getDatabase(dbName);
        this.mName = dbName;
    }

    public MongodbHelper(String ip, int port) {
        if (ip == null) {
            throw new IllegalArgumentException(ip + " is NULL");
        }
        if (port > 65534 || port < 0) {
            throw new IllegalArgumentException(port + " Out of Bounds");
        }

        mongoClient = new MongoClient(ip, port);
    }

    public MongoDatabase getMongoDb() {
        return mongoDatabase;
    }

    public MongoDatabase getMongoDb(String name) {
        return mongoClient.getDatabase(name);
    }

    public String getName() {
        return mName;
    }

    public List<String> getDbNames() {
        return mongoClient.getDatabaseNames();
    }

    public CodecRegistry getCommandCodec() {
        return MongoClient.getDefaultCodecRegistry();
    }

    public MongoCollection getEntity(String entityName) {
        if (mongoDatabase == null) {
            throw new NullPointerException("MongoDatabase is NULL");
        }
        return mongoDatabase.getCollection(entityName);
    }

    public String[] getEntityNames() {
        if (mongoDatabase == null) {
            throw new NullPointerException("MongoDatabase is NULL");
        }
        MongoIterable<String> iterable = mongoDatabase.listCollectionNames();
        return null;
    }

    public void insert(MongoCollection table, BasicDBObject document) {
        table.insertOne(document);
    }

    public void insert(MongoCollection table, List<BasicDBObject> document) {
        table.insertMany(document);
    }

    public DeleteResult delete(MongoCollection table, Bson filter) {
        return table.deleteOne(filter);
    }

    public DeleteResult deletes(MongoCollection table, Bson filter) {
        return table.deleteMany(filter);
    }

    public <T> T find(MongoCollection table, Class<T> clazz) {
        FindIterable iter = table.find(clazz);
        MongoCursor cursor = iter.iterator();
        T obj = null;
        while (cursor.hasNext()) {
            obj = (T) cursor.next();
        }

        return obj;
    }

    public <T> T find(MongoCollection table, Bson filter, Class<T> clazz) {
        FindIterable iter = table.find(filter, clazz);
        MongoCursor cursor = iter.iterator();
        T obj = null;
        while (cursor.hasNext()) {
            obj = (T) cursor.next();
        }

        return obj;
    }

    public <T> List<T> finds(MongoCollection table) {
        FindIterable iter = table.find();
        MongoCursor cursor = iter.iterator();
        List<T> result = new ArrayList<>((int) table.count());
        T obj = null;
        while (cursor.hasNext()) {
            obj = (T) cursor.next();
            result.add(obj);
        }
        return result;
    }

    public UpdateResult update(MongoCollection table, Bson queryObj, Bson newObj) {
        return table.updateOne(queryObj, newObj);
    }

    public UpdateResult updates(MongoCollection table, Bson queryObj, Bson newObj) {
        return table.updateMany(queryObj, newObj);
    }

    public Class getDocumentClass(MongoCollection table) {
        return table.getDocumentClass();
    }
}
